#include "iiadd.h" /*The Abstract Data type stuff required for OME*/

#include <time.h>         /* Required for time function, as part of error
                          ** processing
                          */
/*
** Bits and Bobs for the callback block
*/
static  II_STATUS   (*Ingres_trace_function)() = 0;
#ifdef __STDC__
GLOBALDEF II_ERROR_WRITER *usc_error = 0;
GLOBALDEF II_INIT_FILTER  *usc_setup_workspace = 0;
GLOBALDEF II_LO_HANDLER   *usc_lo_handler = 0;
GLOBALDEF II_LO_FILTER    *usc_lo_filter = 0;
#else
GLOBALDEF (*usc_error)() = 0;
GLOBALDEF (*usc_setup_workspace)() = 0;
GLOBALDEF (*usc_lo_handler)() = 0;
GLOBALDEF (*usc_lo_filter)() = 0;
#endif

/* us_error(): This ensures that error messages are correctly formatted with a
**             date and time. It bypasses problems in the usc_error callback
**             function.
*/
void us_error(II_SCB *scb, long err_no, char *err_text)
{
    char msg[300];

    /* variables used to get current time
    ** need a buffer for thread-safe version of ctime, see man ctime
    */
    char errtime_str[26];
    char errtimebuf[26];
    time_t errtime_t;

    /* get current time and convert to nice string */
    time(&errtime_t);
    strncpy(errtime_str, ctime_r(&errtime_t, errtimebuf), 26);
    sprintf(msg, "%sE_OME001 %s", errtime_str, err_text);

    usc_error(scb, err_no, msg);
}; /* us_error */

/*
** User defined datatypes: empty in this case, but handy to have for the
** IIudadt_register routine.
*/
static IIADD_DT_DFN *Datatypes;

/* The Function Executor Code, External Lenspec routines and any supporting
** functions can go in here...
*/

/* Need arrays of 2-byte integers to hold the function argument datatypes
** Here are some examples...
*/
static II_DT_ID  UD_2_INT[]        = {II_INTEGER,  II_INTEGER};
static II_DT_ID  UD_FLOAT_INT[]    = {II_FLOAT,    II_INTEGER};
static II_DT_ID  UD_VC_N_VB[]      = {II_VARCHAR,  II_VBYTE};
static II_DT_ID  UD_VC_N_LVC[]     = {II_VARCHAR,  II_LVCH};
static II_DT_ID  UD_VC_N_LB[]      = {II_VARCHAR,  II_LBYTE};
static II_DT_ID  UD_2_VC[]         = {II_VARCHAR,  II_VARCHAR};
static II_DT_ID  UD_LVC_N_VC[]     = {II_LVCH,     II_VARCHAR};
static II_DT_ID  UD_2_VARBYTE[]    = {II_VBYTE,    II_VBYTE};


/* The fod_id enum set:
** Use enum to start counting the fod_id's from II_OPSTART
*/
enum fod_id {
   UDF_FIRST_FUNCTION = II_OPSTART,
   UDF_NEXT_FUNCTION = 
}; /* fod_id's */

static IIADD_FO_DFN Function_Definitions[] ={
    /* II_AGGREGATE functions:
    **     These are only available from Ingres2006 rls2
    */
    /* II_NORMAL functions: */
    }; /*Function_Definitions, sort by fod_id */

/*
** For each function defined we need a set of Function Instance Definitions.
**
** The fid_id enum set:
** Use enum to start counting the fid_id's from II_FISTART
*/
enum fid_id {
   UDF_FI_FIRST_FID = II_FISTART,
   UDF_FI_NEXT_FID
}; /* fid_id's */
 
static IIADD_FI_DFN Function_Instances[] = {
    /* The Aggregate Functions, go here. */
    /* The Normal Functions, go here.  */
}; /*Function_Instances, sorted by fid_opid */

/* And now the NASTY BIT...
** If provided, IIADD_DEFINITION exists as a compiler-generated data area.
** Do not dynamically allocate this data area or place it on the stack.
*/
static  IIADD_DEFINITION    register_block =
{
    (IIADD_DEFINITION *) 0,    /* add_next */
    (IIADD_DEFINITION *) 0,    /* add_prev */
    sizeof(IIADD_DEFINITION),  /* add_length */
    IIADD_DFN2_TYPE,           /* add_type */
    0,                         /* add_s_reserved */
    0,                         /* add_1_reserved*/
    0,                         /* add_owner */
    0,                         /* add_ascii_id */
    IIADD_CONSISTENT,          /* add_risk_consistency */
    2,       /* Major id */    /* add_major_id  */
    0,       /* minor id */    /* add_minor_id */
    50,                        /* add_l_user_string */
    "UDT demo",                /* add_user_string */
    IIADD_T_FAIL_MASK | IIADD_T_LOG_MASK,    /* add_trace */
    0,                /* add_count
                      ** This field will be filled in by the iiudadt_register.
                      ** This is not a requirement of the function,
                      ** just a convenient place to do it.
                      */
    0,                                                   /* add_dt_cnt */
    (IIADD_DT_DFN *) 0,                                  /* add_dt_dfn */

    (sizeof(Function_Definitions)/sizeof(IIADD_FO_DFN)), /* add_fo_cnt */
    Function_Definitions,                                /* add_fo_dfn */

    (sizeof(Function_Instances)/sizeof(IIADD_FI_DFN)),   /* add_fi_cnt */
    Function_Instances                                   /* add_fi_dfn */
}; /*register_block*/

/*
** Name: IIUDADT_REGISTER    - Add the datatype to the server
**
** Description:
** This routine is called by the DBMS server to add obtain information to
** add the datatype to the server.  It simply fills in the provided
** structure, sets the provided pointer to point to a pointer to this structure
** and returns.
**
*/
II_STATUS
IIudadt_register(
    IIADD_DEFINITION  **ui_block_ptr,
    II_CALLBACKS      *callback_block
    )
{
    /* This uses the global variable register_block, which is of type
    ** II_ADD_DEFINITION.
    */
    register_block.add_count = register_block.add_dt_cnt +
        register_block.add_fo_cnt +
        register_block.add_fi_cnt;
    *ui_block_ptr = &register_block;  /* Point to the first block in the list */

    /*
    ** Note that after this call, the call back block address will
    ** no longer be valid (the function addresses will, but the block
    ** address itself will not).  Therefore, it is necessary to
    ** copy the values in which we are interested before returning.
    */
    if (callback_block && callback_block->ii_cb_version >= II_CB_V1) {
        Ingres_trace_function = callback_block->ii_cb_trace;
        if (callback_block->ii_cb_version >= II_CB_V2) {
            usc_lo_handler      = callback_block->ii_lo_handler_fcn;
            usc_lo_filter       = callback_block->ii_filter_fcn;
            usc_setup_workspace = callback_block->ii_init_filter_fcn;
            usc_error           = callback_block->ii_error_fcn;
            }
        }
    else {
        Ingres_trace_function = 0;
        };
    return(II_OK);
} /*IIudadt_register*/
